PowerOff x64 0.3.3
Technische Dokumentation
=========================

Dokumentationsstand: 06.09.2026
Dokumentiert wird der Quellstand PowerOffFASM.asm aus Paket 0.3.3.4.
Sichtbare Programmversion: PowerOff x64 0.3.3
Assembler: Flat Assembler (FASM), Win64
Zielsystem: Windows 10/11 x64

Entwickelt von
NotCompatible (Basti) + GPT-5.6 Sol

Inspiriert von Jorgen Bosman

Erstellt mit FASM

Referenz des dokumentierten Quelltexts:
SHA-256: 255a1f606d0ceaab6e1e925692a153ece4500584b9c422009c2c3f0b12a238c2
Zeilen im dokumentierten ASM-Quelltext: 1800


1. Zweck des Programms
----------------------

PowerOff x64 ist eine kleine native Windows-Anwendung zur zeit- oder ereignisgesteuerten
Ausführung von Energie- und Sitzungsaktionen. Das Programm orientiert sich funktional an
dem älteren PowerOff von Jorgen Bosman, ist jedoch als neue 64-Bit-Implementierung für
aktuelle Windows-Versionen aufgebaut.

Der Schwerpunkt liegt bewusst auf den Funktionen, die im Alltag tatsächlich benötigt
werden:

- Herunterfahren
- Neustart
- Abmelden
- Standby
- Ruhezustand
- Sofortige Ausführung mit 60-Sekunden-Warnphase
- Countdown
- Ausführung zu einer festen Uhrzeit
- Ausführung nach dem Ende eines ausgewählten Prozesses
- Optionales erzwungenes Schließen blockierender Programme
- Deutsch/Englisch-Umschaltung

Nicht enthalten sind Netzwerk-Fernsteuerung, Wake-on-LAN, Windows-Dienst, Autostart,
Kommandozeilensteuerung oder sonstige Remote-Funktionen.

Das Programm ist als einzelne native EXE gedacht und benötigt keine zusätzliche Runtime.


2. Entwicklungs- und Build-Umgebung
-----------------------------------

Der Quelltext verwendet die Standard-FASM-Win64-Makros:

    include 'win64ax.inc'

Zum Kompilieren wird eine normale FASM/FASMW-Installation mit dem Standard-INCLUDE-
Verzeichnis benötigt.

Typischer Build in FASMW:

1. PowerOffFASM.asm öffnen.
2. Run -> Compile oder Ctrl+F9 auswählen.
3. Die erzeugte EXE starten.

Ein im Entwicklungsverlauf gemeldeter Build mit FASM 1.73.35 hatte eine Größe von
22.528 Bytes. Spätere reine Layout-Anpassungen ändern diese Größe nur geringfügig;
die genaue Dateigröße hängt vom jeweiligen Quellstand ab.

Wichtig bei FASMW: Bereits geöffnete Editor-Tabs können eine ältere Kopie des Quelltexts
im Speicher behalten, wenn die Datei außerhalb von FASMW überschrieben wurde. Vor einem
neuen Build empfiehlt es sich daher, alte Tabs derselben ASM-Datei zu schließen und die
aktuelle Datei neu zu öffnen.


3. Grundarchitektur
-------------------

PowerOff x64 besteht konzeptionell aus fünf Bereichen:

1. GUI-Hauptthread
   - erzeugt Hauptfenster und Warnfenster
   - verarbeitet Benutzereingaben
   - verwaltet Status und Timer
   - führt die eigentliche Windows-Aktion aus

2. Warte-Thread
   - wartet auf Countdown-/Uhrzeitablauf oder auf das Ende eines Prozesses
   - greift nicht direkt auf GUI-Controls zu
   - kommuniziert über PostMessage mit dem Hauptthread

3. Prozessverwaltung
   - liest Prozesse mit Toolhelp32 ein
   - filtert System-/Hintergrundprozesse
   - speichert die PID als Item-Daten des Kombinationsfelds
   - überwacht den gewählten Prozess über ein Prozess-HANDLE

4. Aktionsschicht
   - ExitWindowsEx für Ausschalten/Neustart/Abmelden
   - SetSuspendState für Standby/Ruhezustand
   - Aktivierung von SeShutdownPrivilege, wenn erforderlich

5. Sprachschicht
   - Deutsch und Englisch in getrennten Stringtabellen
   - Pointerblock für die aktuell aktive Sprache
   - Speicherung der gewählten Sprache in HKCU


4. Programmstart und Nachrichtenverarbeitung
--------------------------------------------

Der Einstiegspunkt ist das Label:

    start:

Beim Start geschieht in dieser Reihenfolge:

1. GetModuleHandleA ermittelt die eigene Modulinstanz.
2. ensure_language_initialized bestimmt die Sprache.
3. CreateEventA legt ein manuell rücksetzbares Stop-Ereignis an.
4. CreateDialogParamA erzeugt den Hauptdialog aus IDD_MAIN.
5. Anschließend läuft die normale Windows-Nachrichtenschleife mit GetMessageA.
6. IsDialogMessageA wird zuerst für ein eventuell geöffnetes Warnfenster und danach für
   das Hauptfenster aufgerufen.
7. Nicht von den Dialogen verbrauchte Nachrichten gehen über TranslateMessage und
   DispatchMessageA an Windows.

Das Stop-Ereignis ist ein zentraler Synchronisationsmechanismus. Damit kann der GUI-
Thread einen wartenden Worker-Thread jederzeit wecken und den aktuellen Auftrag abbrechen.


5. GUI und Dialoge
------------------

Das Programm verwendet zwei DIALOGEX-Ressourcentemplates:

- IDD_MAIN    = 101   Hauptfenster
- IDD_WARNING = 102   60-Sekunden-Warnfenster

Die Ressourcentemplates enthalten nur den Dialograhmen. Die eigentlichen Controls werden
zur Laufzeit in WM_INITDIALOG mit CreateWindowExA erzeugt. Dadurch lässt sich das Layout
direkt im Assemblerquelltext ändern.

Das Hauptfenster enthält:

Bereich "Aktion"
- Herunterfahren
- Neustart
- Abmelden
- Standby
- Ruhezustand
- Checkbox "Programme zwangsweise schließen"

Bereich "Wann?"
- Sofort
- Countdown HH:MM:SS
- Uhrzeit HH:MM
- Wenn Prozess beendet
- Prozess-Kombinationsfeld
- Aktualisieren-Button

Unterer Bereich
- Statuszeile
- START
- STOPP
- DE | EN
- Über / About

START und STOPP sind die größeren Hauptschaltflächen. DE | EN und Über/About sind
24 Pixel hoch und schließen unten bündig mit den Hauptschaltflächen ab.

Das Warnfenster ist als Topmost-Dialog angelegt. Es zeigt die verbleibende Zeit und eine
Abbrechen-Schaltfläche an.


6. Interner Zustandsautomat
---------------------------

Der globale Wert "state" kann vier Zustände annehmen:

    STATE_IDLE       = 0
    STATE_WAITING    = 1
    STATE_WARNING    = 2
    STATE_EXECUTING  = 3

Bedeutung:

STATE_IDLE
- keine geplante Aktion aktiv
- START ist verfügbar
- STOPP ist deaktiviert

STATE_WAITING
- Countdown/Uhrzeit/Prozessende wird abgewartet
- START ist deaktiviert
- STOPP ist aktiv

STATE_WARNING
- Warnphase läuft
- Warnfenster ist sichtbar
- ein 1-Sekunden-Windows-Timer zählt herunter

STATE_EXECUTING
- die gewählte Windows-Aktion wird unmittelbar ausgeführt

Nach erfolgreicher oder fehlgeschlagener Aktionsausführung wird über reset_to_idle wieder
in STATE_IDLE gewechselt, sofern Windows nicht bereits herunterfährt oder die Sitzung
beendet.


7. Aktionen
-----------

Interne Aktionscodes:

    ACTION_SHUTDOWN   = 1
    ACTION_RESTART    = 2
    ACTION_LOGOFF     = 3
    ACTION_STANDBY    = 4
    ACTION_HIBERNATE  = 5

7.1 Herunterfahren

Die Anwendung verwendet:

    ExitWindowsEx(EWX_POWEROFF, 0)

Vorher wird versucht, SeShutdownPrivilege zu aktivieren.

Wichtig: EWX_POWEROFF verlangt zusätzlich zum sauberen Windows-Shutdown die Abschaltung
des Rechners. Auf modernen ACPI-Systemen entspricht dies dem erwarteten vollständigen
Ausschalten.

7.2 Neustart

Verwendet:

    ExitWindowsEx(EWX_REBOOT, 0)

Auch hier wird vorher SeShutdownPrivilege aktiviert.

7.3 Abmelden

Verwendet:

    ExitWindowsEx(EWX_LOGOFF, 0)

7.4 Standby und Ruhezustand

SetSuspendState wird nicht statisch importiert. Stattdessen lädt call_suspend_state zur
Laufzeit:

    PowrProf.dll
    SetSuspendState

über LoadLibraryA und GetProcAddress.

Aufrufparameter:

    SetSuspendState(Hibernate, Force, WakeupEventsDisabled)

Hibernate = 0 -> Standby
Hibernate = 1 -> Ruhezustand
Force entspricht der GUI-Option für erzwungenes Schließen.
WakeupEventsDisabled ist 0.

Die DLL wird danach wieder mit FreeLibrary freigegeben.


8. Option "Programme zwangsweise schließen"
---------------------------------------------

Die Checkbox setzt den globalen Wert:

    force_close = 1

Bei Herunterfahren, Neustart und Abmelden wird dann EWX_FORCE zusätzlich zu den normalen
ExitWindowsEx-Flags gesetzt.

Beispiel:

    EWX_POWEROFF | EWX_FORCE

Damit können Programme, die das Herunterfahren wegen eines Dialogs blockieren würden,
zwangsweise beendet werden.

Beispiel: Notepad enthält ungespeicherten Text und würde normalerweise nachfragen, ob die
Datei gespeichert werden soll. Mit aktivierter Force-Option kann Windows diese Nachfrage
überspringen und den Prozess beenden.

ACHTUNG:
EWX_FORCE kann zu Datenverlust führen. Ungespeicherte Änderungen in geöffneten Programmen
können verloren gehen. Die 60-Sekunden-Warnphase von PowerOff bleibt davon unabhängig
bestehen und kann vor Ausführung der Aktion abgebrochen werden.


9. Trigger
----------

Interne Triggercodes:

    TRIGGER_NOW        = 1
    TRIGGER_COUNTDOWN  = 2
    TRIGGER_CLOCK      = 3
    TRIGGER_PROCESS    = 4

9.1 Sofort

"Sofort" bedeutet in dieser Version nicht, dass Windows ohne Vorwarnung unmittelbar
herunterfährt. Stattdessen startet direkt die 60-Sekunden-Warnphase.

9.2 Countdown

Eingabeformat:

    HH:MM:SS

Grenzen:
- Stunden: 0 bis 99
- Minuten: 0 bis 59
- Sekunden: 0 bis 59
- Gesamtzeit darf nicht 0 sein

get_countdown_seconds berechnet:

    Sekunden = Stunden * 3600 + Minuten * 60 + Sekunden

Ist der Countdown länger als 60 Sekunden, wartet ein Worker-Thread zunächst bis zum
Beginn der Warnphase. Die letzten 60 Sekunden werden im Warnfenster heruntergezählt.

Ist der eingegebene Countdown höchstens 60 Sekunden, beginnt die Warnung sofort mit genau
dieser verbleibenden Zeit.

9.3 Feste Uhrzeit

Eingabeformat:

    HH:MM

Grenzen:
- Stunden: 0 bis 23
- Minuten: 0 bis 59

get_clock_delay_seconds liest die lokale Uhrzeit über GetLocalTime und berechnet die
Sekunden bis zum nächsten Auftreten der Zielzeit.

Liegt die eingegebene Uhrzeit für den aktuellen Tag bereits in der Vergangenheit oder ist
sie gerade erreicht, werden 86.400 Sekunden addiert. Die Aktion wird damit für den
nächsten Tag geplant.

Die letzten 60 Sekunden laufen wieder über den Warnungsdialog.

9.4 Ende eines Prozesses

Dies ist eine zentrale Funktion der Anwendung.

Der Benutzer wählt einen Prozess aus der Liste. Beim bewussten Wechsel des Eintrags im
Kombinationsfeld setzt die Oberfläche automatisch den Radiobutton "Wenn Prozess beendet".

Beim Starten des Auftrags:

1. CB_GETCURSEL liest den ausgewählten Listeneintrag.
2. CB_GETITEMDATA liest die dort hinterlegte PID.
3. OpenProcess wird nur mit SYNCHRONIZE geöffnet.
4. Das Prozess-HANDLE wird zusammen mit dem Stop-Ereignis an den Worker übergeben.
5. WaitForMultipleObjects wartet auf:
   - Stop-Ereignis oder
   - Signalisierung des Prozess-HANDLEs.
6. Ein Prozess-HANDLE wird signalisiert, sobald der Prozess beendet ist.
7. Danach startet die 60-Sekunden-Warnung.

Vorteil: Der Prozess muss nicht jede Sekunde über eine neue Prozessliste gesucht werden.
Windows selbst signalisiert exakt das Ende der ausgewählten Prozessinstanz.

Da die PID nur beim Start in ein HANDLE umgesetzt wird, ist auch eine spätere Wieder-
verwendung derselben PID durch einen anderen Prozess während des Wartens kein Problem:
Das HANDLE bleibt an das ursprünglich geöffnete Prozessobjekt gebunden.


10. Prozessliste und Filterung
------------------------------

Die Liste wird in refresh_process_list erzeugt.

Grundlage:

    CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
    Process32First
    Process32Next

Verwendete Struktur:

    PROCESSENTRY32A

Für x64 wird im Quelltext eine Strukturgröße von 304 Bytes verwendet.
Der EXE-Name beginnt bei Offset 44, die Parent-PID liegt bei Offset 32.

Jeder sichtbare Listeneintrag hat die Form:

    programm.exe   [PID 1234]

Die PID wird zusätzlich unsichtbar als Item-Daten des ComboBox-Eintrags gespeichert.

10.1 Filter: eigener Prozess

Die laufende PowerOff-Instanz selbst wird nie angeboten.

10.2 Filter: gleiche Windows-Sitzung

ProcessIdToSessionId wird dynamisch aus Kernel32.dll ermittelt.

Zuerst wird die Session-ID der eigenen PowerOff-Instanz bestimmt. Danach werden nur
Prozesse akzeptiert, deren Session-ID identisch ist.

Dadurch verschwinden insbesondere Dienste aus Session 0 und viele reine Systemprozesse,
ohne deren geschützte Access Tokens öffnen zu müssen.

10.3 Filter: direkte Kinder des DcomLaunch-Servicehosts

PowerOff ermittelt die PID des Windows-Dienstes "DcomLaunch":

1. Advapi32.dll wird geladen.
2. QueryServiceStatusEx wird dynamisch per GetProcAddress ermittelt.
3. OpenSCManagerA öffnet den Service Control Manager.
4. OpenServiceA öffnet "DcomLaunch".
5. QueryServiceStatusEx liefert die PID des Service-Hosts.

Danach werden Prozesse übersprungen, deren direkte Parent-PID dieser DcomLaunch-PID
entspricht.

Das entspricht auf aktuellen Windows-Systemen typischerweise Prozessen, deren Eltern-
prozess der Servicehost

    svchost.exe -k DcomLaunch -p

ist.

10.4 Manuelle Ausschlussliste

Zusätzlich werden folgende bekannte Hintergrund-/Hilfsprozesse per Name ausgeblendet:

    conhost.exe
    crashhelper.exe
    ctfmon.exe
    nvcontainer.exe
    nvsphelper64.exe
    NVIDIA Broadcast.exe
    NVIDIA Overlay.exe
    svchost.exe

Der Vergleich erfolgt mit lstrcmpiA und ist daher nicht von Groß-/Kleinschreibung
abhängig.

Neue manuelle Filter können im Datenbereich ergänzt und in refresh_process_list mit einem
weiteren lstrcmpiA-Vergleich aufgenommen werden.


11. Threading und Synchronisation
---------------------------------

PowerOff verwendet einen Worker-Thread ausschließlich zum Warten. GUI-Operationen werden
nicht aus diesem Thread heraus ausgeführt.

Das vermeidet typische Win32-Probleme durch direkte Cross-Thread-GUI-Manipulation.

Worker-Modi:

    WORKER_TIME     = 1
    WORKER_PROCESS  = 2

WORKER_TIME:
- WaitForSingleObject wartet entweder auf h_stop_event oder auf den Timeout.
- Nach Timeout wird WM_PO_BEGIN_WARNING an das Hauptfenster gepostet.

WORKER_PROCESS:
- WaitForMultipleObjects wartet gleichzeitig auf h_stop_event und h_process_wait.
- Signalisiert der Prozess zuerst, beginnt die Warnphase.
- Signalisiert STOPP zuerst, wird der Auftrag verworfen.

Eigene GUI-Nachrichten:

    WM_PO_BEGIN_WARNING = 0x8001
    WM_PO_WORKER_DONE   = 0x8002

PostMessageA sorgt dafür, dass die Verarbeitung im GUI-Hauptthread erfolgt.


12. Stop-/Abbruchlogik
----------------------

STOPP verhält sich abhängig vom aktuellen Zustand:

Während STATE_WAITING:
- Status wird auf "Wird abgebrochen ..." gesetzt.
- SetEvent(h_stop_event) weckt den Worker.
- Worker räumt ggf. das Prozess-HANDLE auf.
- WM_PO_WORKER_DONE mit wParam=1 setzt die GUI auf Idle zurück.

Während STATE_WARNING:
- KillTimer beendet den 1-Sekunden-Warn-Timer.
- Warnfenster wird zerstört.
- Zustand geht sofort auf STATE_IDLE zurück.

Während STATE_IDLE:
- STOPP hat keine Wirkung.


13. 60-Sekunden-Warnphase
-------------------------

Die Konstante lautet:

    WARNING_SECONDS = 60

begin_warning:
- setzt STATE_WARNING
- deaktiviert START
- aktiviert STOPP
- erzeugt bei Bedarf den Warnungsdialog
- startet TIMER_WARNING mit 1000 ms

Der Timer läuft im Hauptthread. Pro Tick wird warning_sec um 1 reduziert und der Text im
Warnfenster aktualisiert.

Beispiel:

    Herunterfahren in 42 Sekunden.

    Mit ABBRECHEN kann die Aktion gestoppt werden.

Bei 0 Sekunden:
- Timer wird beendet
- Warnfenster wird geschlossen
- STATE_EXECUTING wird gesetzt
- execute_action wird aufgerufen


14. Shutdown-Privileg
---------------------

enable_shutdown_privilege aktiviert das Windows-Privileg:

    SeShutdownPrivilege

Ablauf:

1. GetCurrentProcess
2. OpenProcessToken mit TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
3. LookupPrivilegeValueA("SeShutdownPrivilege")
4. TOKEN_PRIVILEGES-Struktur aufbauen
5. AdjustTokenPrivileges
6. Token-HANDLE schließen

Das Privileg ist für Systemaktionen wie Ausschalten und Neustart relevant.


15. Sprachsystem Deutsch / Englisch
-----------------------------------

Die GUI besitzt eine zentrale String-Umschaltung mit zwei Tabellen:

    LangTableGerman
    LangTableEnglish

Die globalen p_txt_*, p_status_*, p_msg_* und p_action_*-Pointer zeigen jeweils auf die
Strings der aktiven Sprache.

apply_language_pointers kopiert die passenden Pointer in den Pointerblock.

15.1 Automatische Spracherkennung

Beim ersten Start wird standardmäßig Englisch angenommen. Danach versucht das Programm,
GetUserDefaultUILanguage dynamisch aus Kernel32.dll zu laden.

Ist die primäre Windows-Oberflächensprache Deutsch (PRIMARYLANGID = 7), wird Deutsch als
Standard gewählt.

15.2 Gespeicherte Benutzerauswahl

Eine manuelle Auswahl hat Vorrang vor der automatischen Erkennung.

Registry-Pfad:

    HKEY_CURRENT_USER\Software\PowerOffFASM

Wert:

    Language

Mögliche REG_SZ-Inhalte:

    de
    en

Die Anwendung benötigt hierfür keine Administratorrechte, da ausschließlich HKCU
verwendet wird.

15.3 Umschaltung während des Betriebs

Der Button "DE | EN" ruft toggle_language auf:

1. Sprachbit umschalten
2. Pointertabelle neu setzen
3. Auswahl in der Registry speichern
4. apply_language_to_main aktualisiert bereits sichtbare Controls

Auch ein bereits geöffnetes Warnfenster wird neu beschriftet.

15.4 About-Dialog

Deutsch:

    Entwickelt von
    NotCompatible (Basti) + GPT-5.6 Sol

    Inspiriert von Jorgen Bosman

    Erstellt mit FASM

Englisch:

    Developed by
    NotCompatible (Basti) + GPT-5.6 Sol

    Inspired by Jorgen Bosman

    Built with FASM


16. Dynamisch geladene Windows-Funktionen
-----------------------------------------

Einige Funktionen werden absichtlich nicht statisch über win64ax.inc importiert. Grund:
Bestimmte ältere FASM-Include-Versionen kennen die Symbole nicht.

Dynamisch aufgelöst werden:

Kernel32.dll
- ProcessIdToSessionId
- GetUserDefaultUILanguage

Advapi32.dll
- QueryServiceStatusEx

PowrProf.dll
- SetSuspendState

Das Muster lautet jeweils:

    GetModuleHandleA / LoadLibraryA
    GetProcAddress
    indirekter Funktionsaufruf

Bei selbst geladenen DLLs folgt anschließend FreeLibrary.

Diese Vorgehensweise verbessert die Kompilierbarkeit mit älteren Standard-FASM-Includes.


17. Wichtige statisch verwendete Win32-APIs
--------------------------------------------

Fenster / Dialoge:
- CreateDialogParamA
- CreateWindowExA
- GetMessageA
- IsDialogMessageA
- TranslateMessage
- DispatchMessageA
- SendMessageA
- PostMessageA
- SetWindowTextA
- SetDlgItemTextA
- CheckRadioButton
- IsDlgButtonChecked
- EnableWindow
- MessageBoxA
- MessageBeep
- SetTimer / KillTimer

Prozesse / Threads:
- CreateToolhelp32Snapshot
- Process32First
- Process32Next
- OpenProcess
- CreateThread
- WaitForSingleObject
- WaitForMultipleObjects
- CreateEventA
- SetEvent
- ResetEvent
- CloseHandle

System / Energie:
- ExitWindowsEx
- OpenProcessToken
- LookupPrivilegeValueA
- AdjustTokenPrivileges

Dienstabfrage:
- OpenSCManagerA
- OpenServiceA
- CloseServiceHandle

Registry:
- RegOpenKeyExA
- RegQueryValueExA
- RegCreateKeyExA
- RegSetValueExA
- RegCloseKey

Zeit:
- GetLocalTime


18. Speicher- und Handle-Verwaltung
-----------------------------------

Das Programm verwendet keine allgemeine Heap-Allokation für die Kernfunktionen. Die
meisten Datenpuffer liegen statisch im .data-Bereich.

Relevante HANDLEs werden normalerweise explizit geschlossen:

- Snapshot-HANDLE -> CloseHandle
- Prozess-Wait-HANDLE -> CloseHandle
- Worker-HANDLE -> CloseHandle
- Stop-Event -> CloseHandle beim Programmende
- Token-HANDLE -> CloseHandle
- SCM-/Service-HANDLE -> CloseServiceHandle
- dynamisch geladene DLL -> FreeLibrary
- Registry-Key -> RegCloseKey

Diese Architektur hält Speicherverwaltung und Fehlerpfade relativ überschaubar.


19. Ressourcen und Zeichencodierung
-----------------------------------

Die beiden Dialograhmen liegen als DIALOGEX-Ressource in der .rsrc-Sektion. Die dortigen
Dialogtitel und Fontnamen werden als Unicode mit FASMs "du" abgelegt.

Die dynamisch erzeugten Controls und die meisten Texte verwenden dagegen die ANSI-
Varianten der Win32-API (CreateWindowExA, SetWindowTextA usw.).

Für "Über" wird im deutschen Buttontext explizit das Byte 0xDC für "Ü" verwendet. Auf
westlichen Windows-Codepages funktioniert dies korrekt.

Eine mögliche spätere technische Modernisierung wäre die vollständige Umstellung der GUI
auf die W-/Unicode-Varianten der Win32-API. Für Deutsch und Englisch ist dies aktuell
nicht zwingend erforderlich.


20. Fehlerbehandlung
--------------------

Für typische Fehler existieren lokalisierte Meldungen, unter anderem:

- ungültiger Countdown
- ungültige Uhrzeit
- kein Prozess ausgewählt
- Prozess kann nicht geöffnet werden
- Prozess-Snapshot kann nicht erstellt werden
- Worker-Thread kann nicht gestartet werden
- Stop-Ereignis kann nicht erstellt werden
- Windows-Aktion schlägt fehl

Die Fehlerdialoge werden mit MessageBoxA angezeigt.

Bei Fehlern der optional dynamischen Filterfunktionen wird teilweise bewusst degradiert:
Beispielsweise bleibt der DcomLaunch-Zusatzfilter inaktiv, wenn seine PID nicht ermittelt
werden kann. Die Prozessliste kann dennoch weiter aufgebaut werden.

Wenn ProcessIdToSessionId nicht verfügbar ist oder bereits für den eigenen Prozess
scheitert, bleibt die Prozessliste dagegen absichtlich leer, um nicht versehentlich eine
ungefilterte Systemprozessliste anzubieten.


21. Sicherheits- und Datenverlust-Hinweise
-------------------------------------------

1. Die Force-Option kann ungespeicherte Daten zerstören.
2. Die 60-Sekunden-Warnung ist eine Sicherheitsstufe, ersetzt aber keine Datensicherung.
3. Prozessende bedeutet nur, dass genau die ausgewählte Prozessinstanz beendet wurde.
   Bei Anwendungen mit mehreren Prozessen kann ein Hilfsprozess enden, während andere
   Teile derselben Anwendung noch laufen.
4. Standby/Ruhezustand hängen von den Fähigkeiten und Energieeinstellungen des Systems ab.
5. Die Anwendung versucht keine Netzwerk-/Remote-Aktionen und öffnet keine Netzwerkports.


22. Bekannte Grenzen des aktuellen Designs
-------------------------------------------

- Prozessfilterung ist heuristisch: gleiche Session + DcomLaunch-Parent + manuelle Liste.
  Ein Benutzerprozess kann deshalb sichtbar bleiben, obwohl er für den Benutzer nicht
  interessant ist; umgekehrt kann ein manuell gefilterter Prozess bewusst nicht gewählt
  werden.

- Die manuelle Filterliste ist fest in die EXE einkompiliert.

- Es gibt aktuell keine Konfigurationsdatei für Filter, Standardzeiten oder Aktionen.

- Die Sprachwahl ist die einzige persistente Einstellung und wird in HKCU gespeichert.

- Die Uhrzeitplanung ist auf das nächste Auftreten innerhalb von maximal 24 Stunden
  ausgelegt, nicht auf bestimmte Wochentage oder Datumsangaben.

- Es gibt keine Aufgabenliste; gleichzeitig ist genau ein Auftrag aktiv.

- Das Hauptfenster kann während eines laufenden Warte-Threads geschlossen werden. Windows
  beendet beim Prozessende alle verbleibenden Threads; der Worker wird nicht separat vor
  dem Exit gejoint. Für das kleine Hilfsprogramm ist dies praktisch unkritisch, wäre aber
  bei einer größeren Anwendung ein Kandidat für strengere Shutdown-Synchronisation.


23. Erweiterung: Prozessfilter ergänzen
---------------------------------------

Im Datenbereich befinden sich die Filterstrings, zum Beispiel:

    filter_conhost db 'conhost.exe',0

In refresh_process_list folgt für jeden Filter ein Vergleich nach diesem Muster:

    invoke lstrcmpiA,process_entry+PROCESS_EXE_OFFSET,filter_conhost
    test eax,eax
    jz .next

Für einen zusätzlichen Filter sind daher zwei Schritte erforderlich:

1. neuen nullterminierten Namen im Datenbereich anlegen
2. lstrcmpiA-Vergleich vor dem Einfügen in die ComboBox ergänzen


24. Erweiterung: neue Aktion
----------------------------

Für eine zusätzliche Aktion wären typischerweise folgende Stellen anzupassen:

1. ACTION_*-Konstante hinzufügen
2. Control-ID und Radio-Button ergänzen
3. read_action erweitern
4. get_action_name erweitern
5. deutsche und englische Sprachstrings ergänzen
6. execute_action um die tatsächliche Win32-Aktion erweitern
7. ggf. neue Privilegien oder dynamische APIs behandeln


25. Erweiterung: neuer Trigger
------------------------------

Für einen neuen Trigger wären typischerweise anzupassen:

1. TRIGGER_*-Konstante
2. GUI-Control(s)
3. read_trigger
4. start_job
5. ggf. neuer Worker-Modus
6. Abbruchlogik
7. deutsche und englische Strings

Die vorhandene Architektur mit Stop-Event, Worker-Thread und PostMessage eignet sich auch
für weitere wartende Bedingungen.


26. Empfohlene Funktionstests
-----------------------------

26.1 Prozessüberwachung ohne reales Herunterfahren

- Notepad starten.
- Notepad in PowerOff auswählen.
- Prüfen, dass der Prozess-Radiobutton automatisch aktiviert wird.
- START drücken.
- Notepad schließen.
- Prüfen, dass die Warnung mit 60 Sekunden erscheint.
- ABBRECHEN drücken.

26.2 STOPP während Prozesswartezeit

- Prozess auswählen.
- START drücken.
- Prozess nicht schließen.
- STOPP drücken.
- Prüfen, dass PowerOff wieder "Bereit" anzeigt.

26.3 Countdown

- 00:01:10 einstellen.
- START drücken.
- Prüfen, dass nach 10 Sekunden die 60-Sekunden-Warnung beginnt.
- Abbrechen.

26.4 Kurzer Countdown

- 00:00:15 einstellen.
- START drücken.
- Warnfenster muss sofort mit 15 Sekunden beginnen.

26.5 Uhrzeit

- Zielzeit wenige Minuten in die Zukunft setzen.
- Prüfen, dass die Warnung 60 Sekunden vorher beginnt.

26.6 Sprachumschaltung

- DE | EN drücken.
- Prüfen, dass Hauptfenster und Warnfenster sofort umschalten.
- Programm beenden und neu starten.
- Prüfen, dass die gewählte Sprache erhalten bleibt.

26.7 Force-Close

Dieser Test kann Datenverlust verursachen und sollte nur mit Testdaten erfolgen.

- Notepad öffnen und ungespeicherten Text eingeben.
- Force-Option aktivieren.
- Eine Systemaktion auslösen.
- Beobachten, ob Windows den blockierenden Speicherdialog übergeht.

Für Entwicklungstests sollte die eigentliche Systemaktion möglichst zuletzt und nur auf
einem Testsystem bzw. mit vollständig gespeicherten Daten geprüft werden.


27. Vergleich zum historischen PowerOff-Konzept
------------------------------------------------

Die aktuelle FASM-Version übernimmt bewusst die Grundidee des historischen PowerOff:
Eine kleine Oberfläche verbindet eine gewünschte Windows-Aktion mit einem Zeitpunkt oder
einem Ereignis.

Wesentliche Modernisierung der Prozessfunktion:

Historische Varianten nutzten auf NT-Systemen teilweise alte Performance-Counter-/Registry-
Mechanismen zur Prozessauflistung. Genau diese Art der Prozessliste kann auf modernen
Windows-Versionen problematisch sein.

PowerOff x64 verwendet stattdessen:

- Toolhelp32 zur Enumeration
- ProcessIdToSessionId zur Session-Filterung
- OpenProcess(SYNCHRONIZE) zur konkreten Prozessüberwachung
- WaitForMultipleObjects statt periodischem Polling

Damit wird das tatsächliche Ende des gewählten Prozesses direkt durch den Windows-Kernel
signalisiert.


28. Designziele
---------------

Die wichtigsten Designziele der Anwendung sind:

- klein
- schnell
- native x64
- keine externe Runtime
- keine unnötigen Hintergrunddienste
- keine Netzwerkfunktion
- klare, klassische Win32-GUI
- geringe Zahl von Abhängigkeiten
- robuste Prozessende-Erkennung
- jederzeit abbrechbare Wartephase
- Warnung vor einer destruktiven Systemaktion

Die Anwendung soll kein allgemeiner Scheduler und keine Systemverwaltungs-Suite sein,
sondern ein fokussiertes Hilfsprogramm für typische lange Jobs wie Videocodierung,
Downloads, Berechnungen oder andere Prozesse, nach deren Ende der Rechner automatisch
ausgeschaltet werden soll.


29. Kurzüberblick des Kontrollflusses
-------------------------------------

Normaler Prozess-Trigger:

    Benutzer wählt Aktion
        -> Benutzer wählt Prozess
        -> START
        -> OpenProcess(SYNCHRONIZE)
        -> Worker: WaitForMultipleObjects
             |-- STOPP -> Stop-Event -> Auftrag abbrechen
             |
             `-- Prozess endet
                    -> WM_PO_BEGIN_WARNING
                    -> 60-Sekunden-Timer
                    -> ABBRECHEN möglich
                    -> execute_action
                    -> ExitWindowsEx / SetSuspendState

Zeit-Trigger:

    Benutzer wählt Countdown/Uhrzeit
        -> Zeit validieren
        -> Worker wartet bis 60 Sekunden vor Ziel
        -> Warnphase
        -> Aktion


30. Schlussbemerkung
--------------------

PowerOff x64 0.3.3 ist eine gezielt schlanke Neuimplementierung eines bewährten
Arbeitsablaufs: Windows soll eine Energie- oder Sitzungsaktion nicht nur zu einer grob
geschätzten Zeit, sondern auf Wunsch exakt nach dem Ende eines bestimmten Programms
ausführen.

Die Kombination aus Toolhelp32-Prozessliste, echtem Prozess-HANDLE, Kernel-Wartefunktion,
60-Sekunden-Warnung und klassischer Win32-Oberfläche bildet dafür die technische Basis.

